using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using data.contracts;
using modelbuilder.parts;
using NUnit.Framework;

namespace modelbuilder.tests.parts
{
    [TestFixture]
    public class BoardBuilderTests
    {
        private BoardBuilder sut;
        private IEnumerable<Board> result;

        [SetUp]
        public void Setup() {
            sut = new BoardBuilder();
            sut.Out_Result += x => result = x;
        }

        [Test]
        public void Boardname() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] {XDocument.Load(@"Testdaten\a.ebc.xml")}, ""));
            Assert.That(result.Select(x => x.Name), Is.EquivalentTo(new[] {"abc"}));
        }

        [Test]
        public void Wires_are_created() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] {XDocument.Load(@"Testdaten\a.ebc.xml")}, ""));
            Assert.That(result.First().Wires.Select(x => x.From), Is.EquivalentTo(new[] {"producer.output", "consumer.output"}));
            Assert.That(result.First().Wires.Select(x => x.Type), Is.EquivalentTo(new[] {"int", "string"}));
            Assert.That(result.First().Wires.Select(x => x.To), Is.EquivalentTo(new[] {"consumer.input", "this.output"}));
        }

        [Test]
        public void Board_does_not_implement_interface() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] {XDocument.Load(@"Testdaten\a.ebc.xml")}, ""));
            Assert.That(result.First().Interface, Is.Null);
        }

        [Test]
        public void Board_Implements_Interface() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] {XDocument.Load(@"Testdaten\board_implements_interface.ebc.xml")}, ""));
            Assert.That(result.First().Interface, Is.EqualTo("IFoo"));
        }

        [Test]
        public void Namespace() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] {XDocument.Load(@"Testdaten\a.ebc.xml")}, "xyz"));
            Assert.That(result.First().Namespace, Is.EqualTo("xyz"));
        }

        [Test]
        public void One_Using() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] {XDocument.Load(@"Testdaten\board_using_namespace.ebc.xml")}, ""));
            Assert.That(result.First().Usings, Is.EqualTo(new[] {"x.y.z"}));
        }

        [Test]
        public void Multiple_Usings() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] {XDocument.Load(@"Testdaten\board_using_multi_namespaces.ebc.xml")}, ""));
            Assert.That(result.First().Usings, Is.EqualTo(new[] {"a", "b", "c"}));
        }

        [Test]
        public void External() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] {XDocument.Load(@"Testdaten\board_with_external_name.ebc.xml")}, ""));
            Assert.That(result.First().Externals, Is.EqualTo(new[] {"x"}));
        }

        [Test]
        public void Multiple_Externals() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] {XDocument.Load(@"Testdaten\board_with_multiple_external_names.ebc.xml")}, ""));
            Assert.That(result.First().Externals, Is.EqualTo(new[] {"x", "y", "z"}));
        }

        [Test]
        public void Generic_types_with_curly_braces() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] {XDocument.Load(@"Testdaten\board_with_generic_types.ebc.xml")}, ""));
            Assert.That(result.First().Wires.First().From, Is.EqualTo("(Join<int, string, Tuple<int, string>> join).Output"));
            Assert.That(result.First().Wires.First().Type, Is.EqualTo("IList<int>"));
            Assert.That(result.First().Wires.First().To, Is.EqualTo("(IFoo<IList<int>> foo).Input"));
        }

        [Test]
        public void No_dependencies_given() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] { XDocument.Load(@"Testdaten\a.ebc.xml") }, ""));
            Assert.That(result.Select(x => x.Dependencies), Is.EquivalentTo(new[] { new Dependency[]{} }));
        }

        [Test]
        public void One_dependency() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] { XDocument.Load(@"Testdaten\one_dependency.ebc.xml") }, ""));
            Assert.That(result.Select(x => x.Dependencies).First().First().Dependent, Is.EqualTo("producer"));
            Assert.That(result.Select(x => x.Dependencies).First().First().Type, Is.EqualTo("T"));
        }

        [Test]
        public void One_dependency_with_generic_types() {
            sut.In_Process(new Tuple<IEnumerable<XDocument>, string>(new[] { XDocument.Load(@"Testdaten\one_dependency_with_generic_types.ebc.xml") }, ""));
            Assert.That(result.Select(x => x.Dependencies).First().First().Dependent, Is.EqualTo("(P<X>)producer"));
            Assert.That(result.Select(x => x.Dependencies).First().First().Type, Is.EqualTo("Shared<T>"));
        }
    }
}